﻿using System.Diagnostics;

namespace CSharpBasic;

/// <summary>
/// HashSet:
/// 是什么：
///     提供高性能的集合操作。集合是不包含重复元素且其元素没有特定顺序的集合。
/// 优点：
///     
/// 优点的实现方式：
///
/// 参考网址(贼详细)：https://www.dotnetcurry.com/csharp/1362/hashset-csharp-with-examples
/// </summary>
public class HashSetOper
{
    public static void Main()
    {
        new HashSetOper().Test();
    }

    private void Test()
    {
        // EliminateDuplicates();
        // UnionOper();
        // ExceptWithOper();
        // // HashSet.SymmetricExceptWith() 修改 HashSet 对象以包含仅存在于两个集合之一中但不存在于两个集合中的那些元素。所有匹配的元素都将被删除。
        // HashSet2ListAddStringTimePK();
        // HashSet2ListAddIntTimePK();
        // HashSet2ListContainStringTimePK();
        HashSet2ListRemoveStringTimePK();
    }

    /// <summary>
    /// 剔除相同元素
    /// </summary>
    private void EliminateDuplicates()
    {
        Console.WriteLine("Using HashSet");
        //1. Defining String Array (Note that the string "mahesh" is repeated) 
        string[] names = new string[]
        {
            "mahesh", //
            "vikram",
            "mahesh", //
            "mayur",
            "suprotim",
            "saket",
            "manish"
        };
        //2. Length of Array and Printing array
        Console.WriteLine();
        Console.WriteLine("Length of Array " + names.Length);
        Console.WriteLine("The Data in Array");
        foreach (var n in names)
        {
            Console.Write(" ");
            Console.Write(n);
        }

        Console.WriteLine();
        //3. Defining HashSet by passing an Array of string to it
        HashSet<string> hSet = new HashSet<string>(names);
        //4. Count of Elements in HashSet
        Console.WriteLine();
        Console.WriteLine("Count of Data in HashSet " + hSet.Count);
        //5. Printing Data in HashSet, this will eliminate duplication of "mahesh" 
        Console.WriteLine("Data in HashSet");
        foreach (var n in hSet)
        {
            Console.Write(" ");
            Console.Write(n);
        }

        Console.WriteLine();
    }

    /// <summary>
    /// 合并 集
    /// </summary>
    private void UnionOper()
    {
        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Cyan,
            "__________________UnionWith_______________________");
        string[] names1 = new string[]
        {
            "mahesh", "sabnis", "manish", "sharma", "saket", "karnik"
        };

        string[] Names2 = new string[]
        {
            "suprotim", "agarwal", "vikram", "pendse", "mahesh", "mitkari"
        };
//2.

        HashSet<string> hSetN1 = new HashSet<string>(names1);
        Console.WriteLine("Data in First HashSet");
        foreach (var n in hSetN1)
        {
            Console.WriteLine(n);
        }

        Console.WriteLine("_______________________________________________________________");
        HashSet<string> hSetN2 = new HashSet<string>(Names2);
        Console.WriteLine("Data in Second HashSet");
        foreach (var n in hSetN2)
        {
            Console.WriteLine(n);
        }

        Console.WriteLine("________________________________________________________________");
//3.
        Console.WriteLine("Data After Union");
        hSetN1.UnionWith(hSetN2);
        foreach (var n in hSetN1)
        {
            Console.WriteLine(n);
        }
    }

    /// <summary>
    /// 删除与另一个集合中匹配的元素
    /// </summary>
    private void ExceptWithOper()
    {
        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Cyan,
            "__________________ExceptWith_______________________");
        string[] names1 = new string[]
        {
            "mahesh", "sabnis", "manish", "sharma", "saket", "karnik"
        };
        string[] Names2 = new string[]
        {
            "mahesh", "suprotim", "agarwal", "vikram", "pendse", "mitkari"
        };
        /// ExceptWith
        Console.WriteLine();
        Console.WriteLine("_________________________________");
        Console.WriteLine("Data in HashSet before using Except With");
        Console.WriteLine("_________________________________");
//storing data of hSetN3 in temporary HashSet
        HashSet<string> hSetN1 = new HashSet<string>(names1);
        foreach (var n in hSetN1)
        {
            Console.WriteLine(n);
        }

        Console.WriteLine("_______________________________________________________________");
        HashSet<string> hSetN2 = new HashSet<string>(Names2);
        Console.WriteLine("Data in Second HashSet");
        foreach (var n in hSetN2)
        {
            Console.WriteLine(n);
        }

        Console.WriteLine("________________________________________________________________");

        Console.WriteLine();
        Console.WriteLine("_________________________________");
        Console.WriteLine("Using Except With");
        Console.WriteLine("_________________________________");
        hSetN1.ExceptWith(hSetN2);
        foreach (var n in hSetN1)
        {
            Console.WriteLine(n);
        }
    }

    /// <summary>
    /// HashSet List 添加相同元素花费时间
    /// </summary>
    private void HashSet2ListAddStringTimePK()
    {
        int size = 550;
        string str = "test";
        string[] strs = new string[size];
        for (int i = 0; i < size; i++)
        {
            strs[i] = str + i;
        }

        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Cyan,
            "__________________AddString_______________________");
        List<string> lstNames = new List<string>();
        var s2 = Stopwatch.StartNew();
        foreach (string s in strs)
        {
            lstNames.Add(s);
        }

        s2.Stop();
        Console.WriteLine(s2.Elapsed.TotalMilliseconds.ToString("0.000 ms"));
        Console.WriteLine();
        Console.WriteLine("Ends Here");

        HashSet<string> _hashSet = new HashSet<string>();
        var s1 = Stopwatch.StartNew();
        foreach (string s in strs)
        {
            _hashSet.Add(s);
        }
        s1.Stop();
        Console.WriteLine(s1.Elapsed.TotalMilliseconds.ToString("0.000 ms"));
        Console.WriteLine();
        Console.WriteLine("Ends Here");
    }
    
    private void HashSet2ListAddIntTimePK()
    {
        int size = 550;
        int[] strs = new int[size];
        for (int i = 0; i < size; i++)
        {
            strs[i] = i;
        }

        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Cyan,
            "__________________AddInt_______________________");
        List<int> lstNames = new List<int>();
        var s2 = Stopwatch.StartNew();
        foreach (int s in strs)
        {
            lstNames.Add(s);
        }

        s2.Stop();
        Console.WriteLine(s2.Elapsed.TotalMilliseconds.ToString("0.000 ms"));
        Console.WriteLine();
        Console.WriteLine("Ends Here");

        HashSet<int> _hashSet = new HashSet<int>();
        var s1 = Stopwatch.StartNew();
        foreach (int s in strs)
        {
            _hashSet.Add(s);
        }
        s1.Stop();
        Console.WriteLine(s1.Elapsed.TotalMilliseconds.ToString("0.000 ms"));
        Console.WriteLine();
        Console.WriteLine("Ends Here");
    }

    /// <summary>
    /// 结果清楚地表明 HashSet 比 List 提供更快的元素查找。
    /// 这是因为 HashSet 中没有重复数据。HashSet 为其中的每个项目维护哈希，
    /// 并将它们排列在单独的桶中，桶中包含存储在 HashSet 中的项目的每个字符的哈希。
    /// 当查找发生时，HashSet 对其进行哈希处理，并将其从第一个字符开始跳转到每个字符的匹配桶中，并从 HashSet 中提取元素。
    /// </summary>
    private void HashSet2ListContainStringTimePK()
    {
        int size = 550;
        string str = "test";
        string[] strs = new string[size];
        for (int i = 0; i < size; i++)
        {
            strs[i] = str + i;
        }
        List<string> lstNames = new List<string>();
        foreach (string s in strs)
        {
            lstNames.Add(s);
        }
        HashSet<string> _hashSet = new HashSet<string>();
        foreach (string s in strs)
        {
            _hashSet.Add(s);
        }
        
        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Cyan,
            "__________________ContainString_______________________");
        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Yellow,
            "__________________List_______________________");
        var s1 = Stopwatch.StartNew();
        foreach (string s in strs)
        {
            lstNames.Contains(s);
        }
        s1.Stop();
        Console.WriteLine(s1.Elapsed.TotalMilliseconds.ToString("0.0000000000 ms"));
        Console.WriteLine();
        
        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Yellow,
            "__________________HashSet_______________________");
        s1.Reset();
        foreach (string s in strs)
        {
            _hashSet.Contains(s);
        }
        s1.Stop();
        Console.WriteLine(s1.Elapsed.TotalMilliseconds.ToString("0.0000000000 ms"));
        Console.WriteLine();
        
        Console.WriteLine("Ends Here");
    }
    
    /// <summary>
    /// HashSet 节约时间
    /// </summary>
    private void HashSet2ListRemoveStringTimePK()
    {
        int size = 550;
        string str = "test";
        string[] strs = new string[size];
        for (int i = 0; i < size; i++)
        {
            strs[i] = str + i;
        }
        List<string> lstNames = new List<string>();
        foreach (string s in strs)
        {
            lstNames.Add(s);
        }
        HashSet<string> _hashSet = new HashSet<string>();
        foreach (string s in strs)
        {
            _hashSet.Add(s);
        }
        Dictionary<int, int> _dictionary = new Dictionary<int, int>();
        _dictionary = null;
        Debug.Assert(_dictionary != null, "expected Dictionary to be non-null");

        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Cyan,
            "__________________RemoveString_______________________");
        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Yellow,
            "__________________List_______________________");
        var s1 = Stopwatch.StartNew();
        foreach (string s in strs)
        {
            lstNames.Remove(s);
        }
        s1.Stop();
        Console.WriteLine(s1.Elapsed.TotalMilliseconds.ToString("0.0000000000 ms"));
        Console.WriteLine();
        
        Helper.HelperTools.Console_WriteLine_ChangeColor(ConsoleColor.Yellow,
            "__________________HashSet_______________________");
        s1.Reset();
        s1.Restart();
        foreach (string s in strs)
        {
            _hashSet.Remove(s);
        }
        s1.Stop();
        Console.WriteLine(s1.Elapsed.TotalMilliseconds.ToString("0.0000000000 ms"));
        Console.WriteLine();
        
        Console.WriteLine("Ends Here");
    }
}